<?php


namespace app\api\service;


use app\api\model\User;
use app\api\model\User as UserModel;
use app\enum\ScopeEnum;
use app\exception\TokenException;
use app\validate\api\WeChatException;
use think\Exception;

class UserToken extends Token
{
    protected $code;
    protected $wxAppID;
    protected $wxAppSecret;
    protected $wxLoginUrl;

    function __construct($code)
    {
        $this->code = $code;
        $this->wxAppID = config('wx.app_id');
        $this->wxAppSecret = config('wx.app_secret');
        $this->wxLoginUrl = sprintf(config('wx.login_url'),$this->wxAppID,$this->wxAppSecret,$this->code);
    }

    /**
     *
     * @throws Exception
     */
    public function get(): string
    {
       $result = curl_get($this->wxLoginUrl);
       // 将字符串 变为 数组
       $wxResult = json_decode($result,true);
       //$wxResult 格式
        //{"session_key":"........",
        //  "expires_in":7200,
        //  "openid":"........."
        // }
       if(empty($wxResult)){
           throw new Exception("获取session_key及openID时异常,微信内部错误");
       }else{
           $loginFail = array_key_exists('errcode',$wxResult);
           if($loginFail){
                $this->processLoginError($wxResult);
           } else{
                return $this->grantToken($wxResult);
           }
       }
    }

    /**
     * @param $wxResult
     *
     * @return string
     * @throws TokenException
     */
    private function grantToken($wxResult): string
    {

        //拿到openid
        //数据库看一下,这个openid是不是已经存在
        //如果存在,则不处理,否则新增一条user记录
        //生成令牌,准备缓存数据,写入缓存
        //把令牌返回打破客户端去
        //key:令牌
        //value:wxResult,uid,scope
        $openid = $wxResult['openid'];
        $result = UserModel::getByOpenID($openid);
        if($result){
            $uid = $result->id;
        }else{
            $uid = $this->newUser($openid);
        }
        $cachedValue = $this->prepareCacheValue($wxResult,$uid);
        $token = $this->saveToCache($cachedValue);
        return $token;
    }

    /**
     * @param $cachedValue
     *
     * @return string
     * @throws TokenException
     */
    private function saveToCache($cachedValue): string
    {
        $key = self::generateToken();
        //数组转为字符串
        $value = json_encode($cachedValue);
        $expire_in = config('setting.token_expire_in');
        $request = cache($key,$value,$expire_in);
        if(!$request){
            throw new TokenException(
                [
                    'msg'=>'服务器缓存异常',
                    'errorCode'=>10005
                ]
            );
        }
        return $key;
    }
    private function prepareCacheValue($wxResult,$uid){
        $cachedValue = $wxResult;
        $cachedValue['uid'] = $uid;
        // scope = 16 代表 App 用户的权限数值
        // scope = 32 代表 CMS (管理员) 的权限数值
        $cachedValue['scope'] = ScopeEnum::User;
        return $cachedValue;
    }
    private function newUser($openid){
        $user = UserModel::create(
            ['openid'=>$openid]
        );
        return $user->id;
    }
    /**
     * @param $wxResult
     *
     * @throws WeChatException
     */
    private function processLoginError($wxResult){
        throw new WeChatException([
            'msg'=>$wxResult['errmsg'],
            'errorCode' => $wxResult['errcode']
        ]);
    }
}